<template>
  <el-row style="margin:-10px">
    <el-col :span="8" style="border-right: 5px solid #c1c0c0;">
      <div id="mountNode"></div>
    </el-col>

    <el-col :span="16" style="padding: 0px 15px;height: 590px;overflow-y: scroll;">
      <el-collapse v-model="activeNames">
        <template v-for="enchiridion in models.guideEnchiridions">
          <el-collapse-item :title="enchiridion.name" :name="enchiridion.id" :key="enchiridion.id">
            <code class="hljs" v-html="enchiridion.content"></code>
          </el-collapse-item>
        </template>
      </el-collapse>
    </el-col>
  </el-row>
</template>
<script>
import G6 from "@antv/g6";
export default {
  props: {
    viewModel: {
      type: Object,
    },
    models: {
      type: Object,
    },
    workflow: {
      type: Object,
    },
  },
  data() {
    return {
      activeNames: [],
      guideLinkMap: new Map(),
      findDoing: false,
    };
  },
  mounted() {
    this.initCollapseActiveNames();
    this.initG6();
  },
  methods: {
    initCollapseActiveNames() {
      const activeNames = [];
      if (this.viewModel && this.viewModel.models) {
        const { guideEnchiridions } = this.viewModel.models;
        if (Array.isArray(guideEnchiridions)) {
          guideEnchiridions.forEach((item) => {
            if (item.isUnfold) {
              activeNames.push(item.id);
            }
          });
        }
        this.activeNames = activeNames;
      }
    },
    initG6() {
      if (this.viewModel && this.viewModel.models) {
        const { guideLinks } = this.viewModel.models;
        const g6Nodes = this.buildG6Nodes(guideLinks);
        if (Array.isArray(g6Nodes)) {
          G6.registerEdge("line-arrow", {
            draw(cfg, group) {
              const { startPoint, endPoint, sourceNode, targetNode } = cfg;
              const keyShape = group.addShape("path", {
                attrs: {
                  path: [
                    [
                      "M",
                      startPoint.x + sourceNode.getBBox().width / 2,
                      startPoint.y + sourceNode.getBBox().height / 2,
                    ],
                    [
                      "L",
                      endPoint.x + targetNode.getBBox().width / 2,
                      endPoint.y - targetNode.getBBox().height / 2 - 5,
                    ],
                  ],
                  stroke: "#91b4d3",
                  lineWidth: 5,
                  opacity: 1,
                  endArrow: {
                    // 自定义箭头指向(0, 0)，尾部朝向 x 轴正方向的 path
                    path: "M 0,0 L 10,5 L 10,-5 Z",
                    // 箭头的偏移量，负值代表向 x 轴正方向移动
                    // d: -10,
                    // v3.4.1 后支持各样式属性
                    fill: "#91b4d3",
                    stroke: "#91b4d3",
                    opacity: 1,
                    // ...
                  },
                },
                // must be assigned in G6 3.3 and later versions. it can be any value you want
                name: "path-shape",
              });
              return keyShape;
            },
          });
          const data = {
            // 点集
            nodes: g6Nodes,
            edges: this.buildG6Edges(guideLinks),
          };
          const graph = new G6.Graph({
            // 1.画图挂载容器id
            container: "mountNode",
            // 1.1容器宽高
            width: 360,
            height: 590,
            fitView: true,
            fitViewPadding: [0, 20, 0, 80],
            // 节点在默认状态下的样式配置（style）和其他配置
            defaultNode: {
              // 节点上的标签文本配置
              labelCfg: {
                // 节点上的标签文本样式配置
                style: {
                  fill: "#000", // 节点标签文字颜色
                  fontSize: 11,
                },
              },
            },
            nodeStateStyles: {
              hover: {
                // keyShape 的状态样式
                fill: "#f1f1f1",
                // name 为 node-label 的子图形在该状态值下的样式
                "node-label": {
                  fontSize: 25,
                },
              },
            },
            //边默认的属性，包括边的一般属性和样式属性（style）。
            defaultEdge: {
              type: "line-arrow",
            },
            layout: {
              type: "dagre",
              rankdir: "TB", // 可选，默认为图的中心
              ranksep: 10,
            },
            modes: {
              default: [
                {
                  type: "tooltip",
                  shouldBegin(e) {
                    return e.item.getModel().linkDesc != undefined;
                  },
                  formatText(model) {
                    return model.linkDesc;
                  },
                  offset: 10,
                },
              ],
            },
          });
          graph.on("node:mouseenter", (evt) => {
            const { item } = evt;
            graph.setItemState(item, "hover", true);
          });

          graph.on("node:mouseleave", (evt) => {
            const { item } = evt;
            graph.setItemState(item, "hover", false);
          });
          graph.on("node:click", (ev) => {
            // const {shape,node} = ev
          });
          // 读取 data 中的数据源到图上
          graph.data(data);
          // 渲染图
          graph.render();
          //fitView: true; //设置是否将图适配到画布中；
          // fitViewPadding: [20, 40, 50, 20]//画布上四周的留白宽度。
        }
      }
    },
    buildStateIcon(item) {
      if (item.status == "doing") {
        return {
          show: true,
          img: "https://gw.alipayobjects.com/zos/basement_prod/c781088a-c635-452a-940c-0173663456d4.svg",
        };
      } else if (item.status == "done") {
        return {
          show: true,
          img: "https://gw.alipayobjects.com/zos/basement_prod/300a2523-67e0-4cbf-9d4a-67c077b40395.svg",
        };
      } else {
        return {
          show: false,
        };
      }
    },
    getNodeStatus(item) {
      if (item.workflowLink && !this.findDoing && this.workflow) {
        item.history = [];
        let workflowLinks = item.workflowLink.split(",");
        for (let index = 0; index < workflowLinks.length; index++) {
          const link = workflowLinks[index];
          let doings = _.filter(this.workflow.history, (h) => {
            return h.taskName == link && h.taskStatus == "processing";
          });
          if (doings && doings.length > 0) {
            item.history = item.history.concat(doings);
            this.findDoing = true;
            item.status = "doing";
            break;
          } else {
            let done = _.findLast(this.workflow.history, (h) => {
              return (
                h.taskName == link &&
                h.taskStatus == "finished" &&
                h.handlerName
              );
            });
            if (done) {
              item.history.push(done);
              item.status = "done";
              break;
            }
          }
        }
      }
      item.status = item.status || "none";
    },
    buildLinkDesc(item) {
      let divider = `<div class="el-divider el-divider--horizontal"><div class="el-divider__text is-left">环节说明</div></div>`;
      if (item.status == "doing") {
        let users = item.history
          .map((h) => {
            return h.handlerName || h.assigneeName;
          })
          .join("、");
        let msg = `<p>正在审批中</p><p>待处理人：${users}</p>`;
        return msg + (item.linkDesc ? `${divider}${item.linkDesc}` : "");
      } else if (item.status == "done") {
        let msg = "";
        item.history.forEach((h) => {
          msg += `<p>处理人：${h.handlerName}</p><p>处理时间：${
            h.finishTime
          }</p><p>审批意见：${h.opinionText || "(未填写)"}</p>`;
        });
        return msg + (item.linkDesc ? `${divider}${item.linkDesc}` : "");
      } else {
        return item.linkDesc;
      }
    },
    buildG6Nodes(guideLinks) {
      const nodes = [];
      if (Array.isArray(guideLinks)) {
        guideLinks
          .sort((a, b) => {
            return a.sort - b.sort;
          })
          .forEach((item) => {
            this.getNodeStatus(item);
            let node = {
              id: item.linkId,
              type: "modelRect",
              label: item.linkName,
              description: item.linkProfile,
              linkDesc: this.buildLinkDesc(item),
              size: [300, 80],
              stateIcon: this.buildStateIcon(item),
              labelCfg: {
                style: {
                  fontSize: 18,
                },
              },
            };
            if (item.status == "doing") {
              node.style = {
                stroke: "#ff4949",
              };
              node.preRect = {
                show: true,
                fill: "#ff4949",
              };
            }
            nodes.push(node);
          });
      }
      return nodes;
    },
    buildG6Edges(guideLinks) {
      const edges = [];
      if (Array.isArray(guideLinks) && guideLinks.length > 1) {
        const maxIndex = guideLinks.length - 1;
        guideLinks.forEach((item, index) => {
          if (index != maxIndex) {
            edges.push({
              source: guideLinks[index].linkId,
              target: guideLinks[index + 1].linkId,
            });
          }
        });
      }
      return edges;
    },
  },
};
</script>
<style scoped>
.divider {
  min-height: 590px;
  height: 100%;
}
>>> .g6-tooltip {
  padding: 10px 6px;
  color: #444;
  background-color: rgba(255, 255, 255, 0.9);
  border: 1px solid #e2e2e2;
  border-radius: 4px;
}
>>> .g6-tooltip p {
  white-space: pre-wrap;
  max-width: 400px;
  text-overflow: ellipsis;
}
>>> .hljs p {
  margin: 0px;
}
>>> .hljs img {
  width: 100%;
}
</style>

